package com.hssy.wululuaplan.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hssy.wululuaplan.entity.*;
import com.hssy.wululuaplan.exception.CustomException;
import com.hssy.wululuaplan.mapper.*;
import com.hssy.wululuaplan.service.AttendanceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hssy.wululuaplan.service.ClassRemainService;
import com.hssy.wululuaplan.service.DivideClassService;
import com.hssy.wululuaplan.vo.AttendanceCaseVo;
import com.hssy.wululuaplan.vo.AttendanceCaseVo2;
import com.hssy.wululuaplan.vo.ClassRecordVo;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * <p>
 * 考勤表 服务实现类
 * </p>
 *
 * @author Mr.Hongtao
 * @since 2024-02-28
 */
@Service
public class AttendanceServiceImpl extends ServiceImpl<AttendanceMapper, Attendance> implements AttendanceService {

    @Resource
    private StudentMapper studentMapper;

    @Resource
    private DivideClassService divideClassService;

    @Resource
    private CourseScheduleMapper courseScheduleMapper;

    @Resource
    private CourseMapper courseMapper;

    @Resource
    private ClassRemainMapper classRemainMapper;

    @Resource
    private ClassRemainService classRemainService;

    @Resource
    private AttendanceService attendanceService;

    @Override
    public AttendanceCaseVo findAttendanceByScheduleId(Integer scheduleId) {
        // 准备返回对象
        AttendanceCaseVo vo = new AttendanceCaseVo();
        // 查询该课程计划的签到情况
        List<Attendance> attendanceList = baseMapper.selectList(Wrappers.<Attendance>lambdaQuery()
                .eq(Attendance::getScheduleId, scheduleId));
        // 查询班级的指定学生
        CourseSchedule courseSchedule = courseScheduleMapper.selectById(scheduleId); // 根据计划号拿到课程id
        Integer courseId = courseSchedule.getCourseId();
        List<Student> all = divideClassService.findStudentListByCourseId(courseId); // 再根据课程id拿到全部学生信息
        // 如果该计划的签到记录没有，则直接返回
        if (attendanceList == null || attendanceList.size() <= 0) {
            vo.setMissList(all);
            vo.setCheckinList(new ArrayList<>());
            return vo;
        }
        // 否则就有签到记录
        List<Integer> studentIds = attendanceList.stream().map(Attendance::getStudentId).collect(Collectors.toList());
        List<Student> checkinList = studentMapper.selectBatchIds(studentIds);
        List<Student> missList = new ArrayList<>();
        for (Student student : all) {
            if (!studentIds.contains(student.getId())) {
                missList.add(student);
            }
        }
        vo.setMissList(missList);
        vo.setCheckinList(checkinList);

        return vo;
    }

    @Override
    @Transactional
    public Integer attendance(Integer scheduleId, Integer studentId) {
        // 查询当前学生id是否属于未考勤范围
        AttendanceCaseVo vo = this.findAttendanceByScheduleId(scheduleId);
        List<Integer> missIds = vo.getMissList().stream().map(Student::getId).collect(Collectors.toList());
        Map<Integer, String> studentMap = vo.getMissList().stream().collect(Collectors.toMap(Student::getId, Student::getStudentName));
        if (!missIds.contains(studentId)) {
            throw new CustomException(-100, "当前学生不属于未考勤列表中的一员");
        }

        // 属于未考勤学生，先查看是否还有剩余课时
        ClassRemain classRemain = classRemainMapper.selectOne(Wrappers.<ClassRemain>lambdaQuery()
                .eq(ClassRemain::getStudentId, studentId)
                .last("limit 1"));
        if (classRemain.getRemain() <= 0) {
            return 2;
        }
        // 属于未考勤学生，有剩余课时，设置为考勤
        // 先查看这个计划，这个学生是否有考勤过
        Attendance attendance = baseMapper.selectOne(Wrappers.<Attendance>lambdaQuery()
                .eq(Attendance::getScheduleId, scheduleId)
                .eq(Attendance::getStudentId, studentId)
                .last("limit 1"));
        if (attendance == null) {
            // 该学生还没有在此次课程签到
            Attendance entity = new Attendance();
            entity.setScheduleId(scheduleId);
            entity.setStudentId(studentId);
            entity.setStudentName(studentMap.get(studentId));
            baseMapper.insert(entity);
            // 剩余课时-1
            Integer remain = classRemain.getRemain();
            classRemain.setRemain(remain - 1);
            classRemainMapper.updateById(classRemain);
        }

        return 1;
    }

    @Override
    public List<ClassRecordVo> findSignInRecordListByStudentId(Integer studentId) {
        // 查询签到数据
        List<Attendance> list = baseMapper.selectList(Wrappers.<Attendance>lambdaQuery()
                .eq(Attendance::getStudentId, studentId)
                .eq(Attendance::getStatus, 1));
        // 获取全部计划id
        List<Integer> scheduleIdList = list.stream().map(Attendance::getScheduleId).collect(Collectors.toList());
        // 如果没有签到过，则直接返回空
        if (scheduleIdList.isEmpty()) {
            return new ArrayList<>();
        }
        // 该学生全部签到的课程计划
        List<CourseSchedule> courseScheduleList = courseScheduleMapper.selectList(Wrappers.<CourseSchedule>lambdaQuery()
                .in(CourseSchedule::getId, scheduleIdList)
                        .ne(CourseSchedule::getStart, 0)
                .orderByDesc(CourseSchedule::getStart));
        // 根据签到的课程计划拿到全部课程
        List<Integer> courseIds = courseScheduleList.stream().map(CourseSchedule::getCourseId).collect(Collectors.toList());
        List<Course> courseList = courseMapper.selectBatchIds(courseIds);
        // 将课程映射成map，课程id对应课程全部信息
        Map<Integer, Course> courseMap = courseList.stream().collect(Collectors.toMap(Course::getId, Function.identity()));
        // 最后封装
        List<ClassRecordVo> resultList = new ArrayList<>();
        for (CourseSchedule item : courseScheduleList) {
            ClassRecordVo vo = new ClassRecordVo();
            BeanUtils.copyProperties(item, vo);
            String classTime = DateUtil.format(item.getStart(),"yyyy-MM-dd HH:mm") + " - " +
                    DateUtil.format(item.getEnd(), "HH:mm");
            vo.setClassTime(classTime);
            Course course = courseMap.get(item.getCourseId());
            vo.setCourseName(course.getCourseName());
            vo.setSession(course.getSession());
            vo.setTeacher(course.getTeacher());
            resultList.add(vo);
        }
        return resultList;
    }

    @Override
    public List<AttendanceCaseVo2> findAttendanceByScheduleIdV2(Integer scheduleId) {
        //
        List<AttendanceCaseVo2> resultList = new ArrayList<>();
        CourseSchedule courseSchedule = courseScheduleMapper.selectById(scheduleId); // 根据计划号拿到课程签到状态
        List<Attendance> attendances = baseMapper.selectList(Wrappers.<Attendance>lambdaQuery()
                .eq(Attendance::getScheduleId, scheduleId));
        for (Attendance attendance : attendances) {
            AttendanceCaseVo2 vo2 = new AttendanceCaseVo2();
            vo2.setId(attendance.getStudentId());
            vo2.setStudentName(attendance.getStudentName());
            vo2.setSignFlag(attendance.getStatus() == 1);
            vo2.setStatus(courseSchedule.getStatus()); // 计划状态
            resultList.add(vo2);
        }

        // // 查询该课程计划的签到情况
        // List<Attendance> attendanceList = baseMapper.selectList(Wrappers.<Attendance>lambdaQuery()
        //         .eq(Attendance::getScheduleId, scheduleId));
        // // 查询班级的指定学生
        // CourseSchedule courseSchedule = courseScheduleMapper.selectById(scheduleId); // 根据计划号拿到课程id
        // Integer courseId = courseSchedule.getCourseId();
        // List<Student> all = divideClassService.findStudentListByCourseId(courseId); // 再根据课程id拿到全部学生信息
        // // 如果该计划的签到记录没有，则直接返回
        // List<AttendanceCaseVo2> resultList = new ArrayList<>();
        // if (attendanceList == null || attendanceList.size() <= 0) {
        //     for (Student student : all) {
        //         AttendanceCaseVo2 vo2 = new AttendanceCaseVo2();
        //         BeanUtils.copyProperties(student, vo2);
        //         vo2.setSignFlag(false);
        //         vo2.setStatus(courseSchedule.getStatus());
        //         resultList.add(vo2);
        //     }
        //     return resultList;
        // }
        // // 否则就有签到记录
        // List<Integer> studentIds = attendanceList.stream().map(Attendance::getStudentId).collect(Collectors.toList());
        //
        // for (Student student : all) {
        //     AttendanceCaseVo2 vo2 = new AttendanceCaseVo2();
        //     BeanUtils.copyProperties(student, vo2);
        //     vo2.setSignFlag(studentIds.contains(student.getId()));
        //     vo2.setStatus(courseSchedule.getStatus());
        //     resultList.add(vo2);
        // }
        return resultList;
    }

    @Override
    @Transactional
    public void batchAttendance(Integer scheduleId, List<Integer> studentIds) {
        // 1. 删除该计划id之前保存的全部签到记录
        // 1.1 先查出涉及到的全部原始学生id
        List<Attendance> attendances = baseMapper.selectList(Wrappers.<Attendance>lambdaQuery()
                .eq(Attendance::getScheduleId, scheduleId));
        List<Integer> originStudentIds = attendances.stream()
                .filter(attendance -> attendance.getStatus().equals(1))
                .map(Attendance::getStudentId)
                .collect(Collectors.toList());
        // 1.2 删除（其实不用删除，把它们的状态status设置为0）
        for (Attendance attendance : attendances) {
            attendance.setStatus(0);
        }
        this.saveOrUpdateBatch(attendances);
        // 1.3 恢复之前被删除学生的课时数
        if (originStudentIds.size() > 0) {
            List<ClassRemain> originClassRemainList = classRemainMapper.selectList(
                    Wrappers.<ClassRemain>lambdaQuery()
                            .in(ClassRemain::getStudentId, originStudentIds));
            for (ClassRemain classRemain : originClassRemainList) {
                Integer remain = classRemain.getRemain();
                classRemain.setRemain(remain + 1);// 剩余课时 + 1
            }
            classRemainService.updateBatchById(originClassRemainList);
        }


        // 2. 重新批量添加签到记录
        List<Attendance> saveList = new ArrayList<>();
        // 3. 查询该班所有学生
        CourseSchedule one = courseScheduleMapper.selectOne(Wrappers.<CourseSchedule>lambdaQuery()
                .eq(CourseSchedule::getId, scheduleId)
                .last("limit 1"));
        Map<Integer, String> allMap = new HashMap<>();
        if (one != null) {
            List<DivideClass> list = divideClassService.list(Wrappers.<DivideClass>lambdaQuery()
                    .eq(DivideClass::getCourseId, one.getCourseId()));
            List<Integer> allStudentIds = list.stream().map(DivideClass::getStudentId).collect(Collectors.toList());
            List<Student> allStudentList = studentMapper.selectList(Wrappers.<Student>lambdaQuery()
                    .in(Student::getId, allStudentIds)
                    .eq(Student::getDeleteFlag, 0));
            allMap = allStudentList.stream()
                    .collect(Collectors.toMap(Student::getId, Student::getStudentName));
        }

        if (studentIds.size() > 0) {
            List<Student> students = studentMapper.selectBatchIds(studentIds);
            // 签到的设置为1
            for (Student student : students) {
                Attendance entity = new Attendance();
                entity.setScheduleId(scheduleId);
                entity.setStudentId(student.getId());
                entity.setStudentName(student.getStudentName());
                entity.setStatus(1);
                saveList.add(entity);
            }
            // 缺勤的设置为0
            for (Map.Entry<Integer, String> entry : allMap.entrySet()) {
                if (!studentIds.contains(entry.getKey())) {
                    Attendance entity = new Attendance();
                    entity.setScheduleId(scheduleId);
                    entity.setStudentId(entry.getKey());
                    entity.setStudentName(entry.getValue());
                    entity.setStatus(0);
                    saveList.add(entity);
                }
            }
            attendanceService.saveBatch(saveList);

            // 3. 重新计算这些学生的剩余课时
            List<ClassRemain> classRemainList = classRemainMapper.selectList(Wrappers.<ClassRemain>lambdaQuery()
                    .in(ClassRemain::getStudentId, studentIds));
            for (ClassRemain classRemain : classRemainList) {
                // 剩余课时-1
                Integer remain = classRemain.getRemain();
                classRemain.setRemain(remain - 1);
            }
            classRemainService.updateBatchById(classRemainList);
        }else {
            // 否则全部设置为缺勤 0
            for (Map.Entry<Integer, String> entry : allMap.entrySet()) {
                Attendance entity = new Attendance();
                entity.setScheduleId(scheduleId);
                entity.setStudentId(entry.getKey());
                entity.setStudentName(entry.getValue());
                entity.setStatus(0);
                saveList.add(entity);
            }
            attendanceService.saveBatch(saveList);
        }



        // 4. 最后修改计划的签到状态
        CourseSchedule courseSchedule = courseScheduleMapper.selectById(scheduleId);
        courseSchedule.setStatus(studentIds.size() > 0 ? 1 : 2);
        courseScheduleMapper.updateById(courseSchedule);

    }

    @Override
    public Integer getStatus(Integer scheduleId) {
        CourseSchedule courseSchedule = courseScheduleMapper.selectById(scheduleId);
        if (courseSchedule != null) {
            return courseSchedule.getStatus();
        }else {
            return null;
        }
    }

    @Override
    public Long findNoFinish() {
        return courseScheduleMapper.selectCount(Wrappers.<CourseSchedule>lambdaQuery()
                .eq(CourseSchedule::getStatus, 0)
                .eq(CourseSchedule::getDeleteFlag, 0));
    }
}
